package com.googlecode.cnasort.cc.rmi.server.core;

import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.rmi.RemoteException;
import org.apache.log4j.Logger;
import com.googlecode.cnasort.cc.rmi.common.RMIFileImpl;
import com.googlecode.cnasort.cc.rmi.common.data.RMIDirectory;
import com.googlecode.cnasort.cc.rmi.common.data.RMIFile;
import com.googlecode.cnasort.cc.rmi.common.data.RMIFileLoader;
import com.googlecode.cnasort.cc.rmi.common.data.RMIFileLoaderId;
import com.googlecode.cnasort.cc.rmi.common.data.impl.RMIDirectoryImpl;

public class RMIFileLoaderImpl implements RMIFileLoader
{
    //private static final long serialVersionUID = 4949933229752340462L;
    private static final Logger logger = Logger.getLogger( RMIFileLoaderImpl.class );

    private RMIFileLoaderId id;

    private byte[]      fileTransfertBuffer;
    private InputStream fileTransfertInputStream;
    private boolean     fileTransfertDone = true;

    public RMIFileLoaderImpl(RMIFileLoaderId id) //throws RemoteException
    {
        this.id = id;

        setFileTransfertBufferSize( 1024 * 1024 );
    }

    //public RMIFileLoaderImpl() throws RemoteException {}

    @Override
    public RMIDirectory[] getRootDirectories() //throws RemoteException
    {
        if( logger.isTraceEnabled() ) {
            logger.trace("[S] getRootDirectories() called by " + id );
            }

        File[] roots = File.listRoots();

        if( roots == null ) {
            return new RMIDirectory[ 0 ];
            }

        RMIDirectory[] dirs  = new RMIDirectory[ roots.length ];

        for( int i = 0; i<roots.length; i++ ) {
            dirs[ i ] = new RMIDirectoryImpl( roots[ i ] );
            }

        return dirs;
    }

    @Override
    public RMIDirectory[] getDirectories(RMIDirectory directory) //throws RemoteException
    {
        File[] files = directory.getPath().toFile().listFiles( new FileFilter() {
            @Override
            public boolean accept(File pathname)
            {
                return pathname.isDirectory();
            }} );

        if( files == null ) {
            return new RMIDirectory[ 0 ];
            }

        RMIDirectory[] dirs  = new RMIDirectory[ files.length ];

        for( int i = 0; i<files.length; i++ ) {
            dirs[ i ] = new RMIDirectoryImpl( files[ i ] );
            }

        return dirs;
    }

    @Override
    public RMIFile[] getFiles(RMIDirectory directory)
    {
        File[] files = directory.getPath().toFile().listFiles( new FileFilter() {
            @Override
            public boolean accept(File pathname)
            {
                return !pathname.isDirectory();
            }} );

        if( files == null ) {
            return new RMIFile[ 0 ];
            }

        RMIFile[] fs  = new RMIFile[ files.length ];

        for( int i = 0; i<files.length; i++ ) {
            fs[ i ] = new RMIFileImpl( files[ i ] );
            }

        return fs;
    }

//    @Override
//    public byte[] getFileContent( RMIFile file ) throws RemoteException
//    {
//        ByteArrayOutputStream out = new ByteArrayOutputStream();
//
//        if( logger.isTraceEnabled() ) {
//            logger.trace("[S] getFileContent(" + file + ") called by " + id );
//            }
//
//        try {
//            InputStream fi  = new FileInputStream( file.getPath().toFile() );
//
//            try {
//                byte[] buffer = new byte[1024];
//                int    len;
//
//                while( (len = fi.read( buffer )) >= 0 ) {
//                    out.write(buffer, 0, len);
//                    }
//                }
//            finally {
//                fi.close();
//                }
//            }
//        catch (IOException e) {
//            RemoteException ne = new RemoteException( "getFileContent(" + file + ")" );
//            ne.initCause( e );
//            throw ne;
//            }
//
//        return out.toByteArray();
//    }

    @Override
    public boolean isFileTransfertComplete()
    {
        return fileTransfertDone;
    }

    @Override
    public void openFileTransfert( RMIFile file ) throws RemoteException
    {
        if( fileTransfertInputStream != null ) {
            try { fileTransfertInputStream.close(); } catch( IOException ignore ) {}
            fileTransfertInputStream = null;
            fileTransfertDone = false;
            }

        try {
            fileTransfertInputStream = new FileInputStream( file.getPath().toFile() );
            }
        catch (FileNotFoundException e) {
            RemoteException ne = new RemoteException( "openFileTransfert()" );
            ne.initCause( e );
            throw ne;
        }
    }

    @Override
    public void closeFileTransfert() throws RemoteException
    {
        if( fileTransfertInputStream != null ) {
            try {
                fileTransfertInputStream.close();
                }
            catch( IOException e ) {
                RemoteException ne = new RemoteException( "closeFileTransfert()" );
                ne.initCause( e );
                throw ne;
                }
            finally {
                fileTransfertInputStream = null;
                fileTransfertDone = true;
                }
            }
    }

    @Override
    public byte[] nextFileTransfertPart() throws RemoteException
    {
        int len;

        try {
            len = fileTransfertInputStream.read( fileTransfertBuffer );
            }
        catch (IOException e) {
            RemoteException ne = new RemoteException( "nextFileTransfertPart()" );
            ne.initCause( e );
            throw ne;
            }

        fileTransfertDone = len <= 0;

        byte[] buffer = new byte[ len ];
        System.arraycopy(fileTransfertBuffer, 0, buffer, 0, len);
        return buffer;
    }

    @Override
    public int getFileTransfertBufferSize()
    {
        return fileTransfertBuffer.length;
    }

    @Override
    public void setFileTransfertBufferSize(int maxBufferSize)
    {
        this.fileTransfertBuffer = new byte[ maxBufferSize ];
    }

}
